home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / update~4.z / update~4 / lib_stdio_vfprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-06  |  16.1 KB  |  679 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifdef LIBC_SCCS
  19. static char sccsid[] = "@(#)doprnt.c    5.35 (Berkeley) 6/27/88";
  20. #endif /* LIBC_SCCS */
  21.  
  22. #define __SRC__
  23. #include <sys/types.h>
  24. #include <stdarg.h>
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #ifndef atarist    /* not for TOS lib */
  29. typedef unsigned long u_long;
  30. #endif
  31.  
  32. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  33. #define    MAXEXP        308
  34. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  35. #define    MAXFRACT    39
  36.  
  37. #define    DEFPREC        6
  38.  
  39. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  40.  
  41. #ifndef atarist
  42. /* Putc without line buffering    (adapted from earls stdiolib.h)
  43.  * NOTE:  We dont include stdilib.h because we dont want varargs.h here.
  44.  *
  45.  * This version of putc() should be exactly the same as that declared
  46.  * in stdio.h except that it shouldn't worry about line buffering.
  47.  */
  48. #  define PUTC(x) ( \
  49.     (fp)->_ptr < (fp)->_base + (fp)->_bufsiz \
  50.     ? (int) (*(fp)->_ptr++ = (unsigned char)(x)) \
  51.     : _flsbuf((unsigned char)(x),(fp)) \
  52. )
  53. #else
  54. #  define    PUTC(ch)    (void) putc(ch, fp)
  55. #endif /* atarist */
  56.  
  57.  
  58. #define    ARG() \
  59.     _ulong = flags&LONGINT ? va_arg(argp, long) : \
  60.         flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
  61.  
  62. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  63.  
  64. #define    todigit(c)    ((c) - '0')
  65. #define    tochar(n)    ((n) + '0')
  66.  
  67. #define    LONGINT        0x01        /* long integer */
  68. #define    LONGDBL        0x02        /* long double; unimplemented */
  69. #define    SHORTINT    0x04        /* short integer */
  70. #define    ALT        0x08        /* alternate form */
  71. #define    LADJUST        0x10        /* left adjustment */
  72. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  73. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  74.  
  75. #ifndef __NO_FLOATS__
  76. #define __FLOATS__ 1
  77. #endif
  78.  
  79. #ifdef __FLOATS__
  80. #ifdef __STDC__
  81. static char *exponent(char *, int, int);
  82. static char *round(double, int *, char *, char *, int, char *);
  83. static int  cvt(double, int, int, char *, int, char *, char *);
  84. #else
  85. static char *exponent();
  86. static char *round();
  87. static int  cvt();
  88. #endif
  89. #endif
  90.  
  91. int vfprintf(fp, fmt0, argp)
  92.     register FILE *fp;
  93.     const char *fmt0;
  94.     va_list argp;
  95. {
  96.     register const char *fmt;    /* format string */
  97.     register int ch;    /* character from fmt */
  98.     register int cnt;    /* return value accumulator */
  99.     register int n;        /* random handy integer */
  100.     register char *t;    /* buffer pointer */
  101.     double _double;        /* double precision arguments %[eEfgG] */
  102.     u_long _ulong;        /* integer arguments %[diouxX] */
  103.     int base;        /* base for [diouxX] conversion */
  104.     int dprec;        /* decimal precision in [diouxX] */
  105.     int fieldsz;        /* field size expanded by sign, etc */
  106.     int flags;        /* flags as above */
  107.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  108.     int prec;        /* precision from format (%.3d), or -1 */
  109.     int realsz;        /* field size expanded by decimal precision */
  110.     int size;        /* size of converted field or string */
  111.     int width;        /* width from format (%8d), or 0 */
  112.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  113.     char softsign;        /* temporary negative sign for floats */
  114.     char *digs;        /* digits for [diouxX] conversion */
  115.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  116.  
  117.     fmt = fmt0;
  118.     digs = "0123456789abcdef";
  119.     for (cnt = 0;; ++fmt) {
  120.         if (!(ch = *fmt))
  121.             return (cnt);
  122.         if (ch != '%') {
  123.             PUTC(ch);
  124.             continue;
  125.         }
  126.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  127.         prec = -1;
  128.         sign = '\0';
  129.  
  130. rflag:        switch (*++fmt) {
  131.         case ' ':
  132.             /*
  133.              * ``If the space and + flags both appear, the space
  134.              * flag will be ignored.''
  135.              *    -- ANSI X3J11
  136.              */
  137.             if (!sign)
  138.                 sign = ' ';
  139.             goto rflag;
  140.         case '#':
  141.             flags |= ALT;
  142.             goto rflag;
  143.         case '*':
  144.             /*
  145.              * ``A negative field width argument is taken as a
  146.              * - flag followed by a  positive field width.''
  147.              *    -- ANSI X3J11
  148.              * They don't exclude field widths read from args.
  149.              */
  150.             if ((width = va_arg(argp, int)) >= 0)
  151.                 goto rflag;
  152.             width = -width;
  153.             /* FALLTHROUGH */
  154.         case '-':
  155.             flags |= LADJUST;
  156.             goto rflag;
  157.         case '+':
  158.             sign = '+';
  159.             goto rflag;
  160.         case '.':
  161.             if (*++fmt == '*')
  162.                 n = va_arg(argp, int);
  163.             else {
  164.                 n = 0;
  165.                 while (isascii(*fmt) && isdigit(*fmt))
  166.                     n = TEN_MUL(n) + todigit(*fmt++);
  167.                 --fmt;
  168.             }
  169.             prec = n < 0 ? -1 : n;
  170.             goto rflag;
  171.         case '0':
  172.             /*
  173.              * ``Note that 0 is taken as a flag, not as the
  174.              * beginning of a field width.''
  175.              *    -- ANSI X3J11
  176.              */
  177.             flags |= ZEROPAD;
  178.             goto rflag;
  179.         case '1': case '2': case '3': case '4':
  180.         case '5': case '6': case '7': case '8': case '9':
  181.             n = 0;
  182.             do {
  183.                 n = TEN_MUL(n) + todigit(*fmt);
  184.             } while (isascii(*++fmt) && isdigit(*fmt));
  185.             width = n;
  186.             --fmt;
  187.             goto rflag;
  188.         case 'L':
  189.             flags |= LONGDBL;
  190.             goto rflag;
  191.         case 'h':
  192.             flags |= SHORTINT;
  193.             goto rflag;
  194.         case 'l':
  195.             flags |= LONGINT;
  196.             goto rflag;
  197.         case 'c':
  198.             *(t = buf) = va_arg(argp, int);
  199.             size = 1;
  200.             sign = '\0';
  201.             goto pforw;
  202.         case 'D':
  203.             flags |= LONGINT;
  204.             /*FALLTHROUGH*/
  205.         case 'd':
  206.         case 'i':
  207.             ARG();
  208.             if ((long)_ulong < 0) {
  209.                 _ulong = -_ulong;
  210.                 sign = '-';
  211.             }
  212.             base = 10;
  213.             goto number;
  214. #ifdef __FLOATS__
  215.         case 'e':
  216.         case 'E':
  217.         case 'f':
  218.         case 'g':
  219.         case 'G':
  220.             _double = va_arg(argp, double);
  221.             /*
  222.              * don't do unrealistic precision; just pad it with
  223.              * zeroes later, so buffer size stays rational.
  224.              */
  225.             if (prec > MAXFRACT) {
  226.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  227.                     fpprec = prec - MAXFRACT;
  228.                 prec = MAXFRACT;
  229.             }
  230.             else if (prec == -1)
  231.                 prec = DEFPREC;
  232.             /*
  233.              * softsign avoids negative 0 if _double is < 0 and
  234.              * no significant digits will be shown
  235.              */
  236.             if (_double < 0) {
  237.                 softsign = '-';
  238.                 _double = -_double;
  239.             }
  240.             else
  241.                 softsign = 0;
  242.             /*
  243.              * cvt may have to round up past the "start" of the
  244.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  245.              * if the first char isn't NULL, it did.
  246.              */
  247.             *buf = '\0';
  248.             size = cvt(_double, prec, flags, &softsign, *fmt, buf,
  249.                 buf + sizeof(buf));
  250.             if (softsign)
  251.                 sign = '-';
  252.             t = *buf ? buf : buf + 1;
  253.             goto pforw;
  254. #endif /* __FLOATS__ */
  255.         case 'n':
  256.             if (flags & LONGINT)
  257.                 *va_arg(argp, long *) = cnt;
  258.             else if (flags & SHORTINT)
  259.                 *va_arg(argp, short *) = cnt;
  260.             else
  261.                 *va_arg(argp, int *) = cnt;
  262.             break;
  263.         case 'O':
  264.             flags |= LONGINT;
  265.             /*FALLTHROUGH*/
  266.         case 'o':
  267.             ARG();
  268.             base = 8;
  269.             goto nosign;
  270.         case 'p':
  271.             /*
  272.              * ``The argument shall be a pointer to void.  The
  273.              * value of the pointer is converted to a sequence
  274.              * of printable characters, in an implementation-
  275.              * defined manner.''
  276.              *    -- ANSI X3J11
  277.              */
  278.             /* NOSTRICT */
  279.             _ulong = (u_long)va_arg(argp, void *);
  280.             base = 16;
  281.             goto nosign;
  282.         case 's':
  283.             if (!(t = va_arg(argp, char *)))
  284.                 t = "(null)";
  285.             if (prec >= 0) {
  286.                 /*
  287.                  * can't use strlen; can only look for the
  288.                  * NUL in the first `prec' characters, and
  289.                  * strlen() will go further.
  290.                  */
  291.                 char *p;
  292.                 void *memchr();
  293.  
  294.                 if (p = (char *)memchr(t, 0, prec)) {
  295.                     size = p - t;
  296.                     if (size > prec)
  297.                         size = prec;
  298.                 } else
  299.                     size = prec;
  300.             } else
  301.                 size = strlen(t);
  302.             sign = '\0';
  303.             goto pforw;
  304.         case 'U':
  305.             flags |= LONGINT;
  306.             /*FALLTHROUGH*/
  307.         case 'u':
  308.             ARG();
  309.             base = 10;
  310.             goto nosign;
  311.         case 'X':
  312.             digs = "0123456789ABCDEF";
  313.             /* FALLTHROUGH */
  314.         case 'x':
  315.             ARG();
  316.             base = 16;
  317.             /* leading 0x/X only if non-zero */
  318.             if (flags & ALT && _ulong != 0)
  319.                 flags |= HEXPREFIX;
  320.  
  321.             /* unsigned conversions */
  322. nosign:            sign = '\0';
  323.             /*
  324.              * ``... diouXx conversions ... if a precision is
  325.              * specified, the 0 flag will be ignored.''
  326.              *    -- ANSI X3J11
  327.              */
  328. number:            if ((dprec = prec) >= 0)
  329.                 flags &= ~ZEROPAD;
  330.  
  331.             /*
  332.              * ``The result of converting a zero value with an
  333.              * explicit precision of zero is no characters.''
  334.              *    -- ANSI X3J11
  335.              */
  336.             t = buf + BUF;
  337.             if (_ulong != 0 || prec != 0) {
  338.                 do {
  339.                     *--t = digs[_ulong % base];
  340.                     _ulong /= base;
  341.                 } while (_ulong);
  342.                 digs = "0123456789abcdef";
  343.                 if (flags & ALT && base == 8 && *t != '0')
  344.                     *--t = '0'; /* octal leading 0 */
  345.             }
  346.             size = buf + BUF - t;
  347.  
  348. pforw:
  349.             /*
  350.              * All reasonable formats wind up here.  At this point,
  351.              * `t' points to a string which (if not flags&LADJUST)
  352.              * should be padded out to `width' places.  If
  353.              * flags&ZEROPAD, it should first be prefixed by any
  354.              * sign or other prefix; otherwise, it should be blank
  355.              * padded before the prefix is emitted.  After any
  356.              * left-hand padding and prefixing, emit zeroes
  357.              * required by a decimal [diouxX] precision, then print
  358.              * the string proper, then emit zeroes required by any
  359.              * leftover floating precision; finally, if LADJUST,
  360.              * pad with blanks.
  361.              */
  362.  
  363.             /*
  364.              * compute actual size, so we know how much to pad
  365.              * fieldsz excludes decimal prec; realsz includes it
  366.              */
  367.             fieldsz = size + fpprec;
  368.             if (sign)
  369.                 fieldsz++;
  370.             if (flags & HEXPREFIX)
  371.                 fieldsz += 2;
  372.             realsz = dprec > fieldsz ? dprec : fieldsz;
  373.  
  374.             /* right-adjusting blank padding */
  375.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  376.                 for (n = realsz; n < width; n++)
  377.                     PUTC(' ');
  378.             /* prefix */
  379.             if (sign)
  380.                 PUTC(sign);
  381.             if (flags & HEXPREFIX) {
  382.                 PUTC('0');
  383.                 PUTC((char)*fmt);
  384.             }
  385.             /* right-adjusting zero padding */
  386.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  387.                 for (n = realsz; n < width; n++)
  388.                     PUTC('0');
  389.             /* leading zeroes from decimal precision */
  390.             for (n = fieldsz; n < dprec; n++)
  391.                 PUTC('0');
  392.  
  393.             /* the string or number proper */
  394.             for (n = size; --n >= 0; )
  395.                 PUTC(*t++);
  396.             /* trailing f.p. zeroes */
  397.             while (--fpprec >= 0)
  398.                 PUTC('0');
  399.             /* left-adjusting padding (always blank) */
  400.             if (flags & LADJUST)
  401.                 for (n = realsz; n < width; n++)
  402.                     PUTC(' ');
  403.             /* finally, adjust cnt */
  404.             cnt += width > realsz ? width : realsz;
  405.             break;
  406.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  407.             return (cnt);
  408.         default:
  409.             PUTC((char)*fmt);
  410.             cnt++;
  411.         }
  412.     }
  413.     /* NOTREACHED */
  414. }
  415.  
  416. #ifdef __FLOATS__
  417. static
  418. cvt(number, prec, flags, signp, fmtch, startp, endp)
  419.     double number;
  420.     register int prec;
  421.     int flags;
  422.     char fmtch;
  423.     char *signp, *startp, *endp;
  424. {
  425.     register char *p, *t;
  426.     register double fract;
  427.     int dotrim, expcnt, gformat;
  428.     double integer, tmp, modf();
  429.     char *exponent(), *round();
  430.  
  431.     dotrim = expcnt = gformat = 0;
  432.     fract = modf(number, &integer);
  433.  
  434.     /* get an extra slot for rounding. */
  435.     t = ++startp;
  436.  
  437.     /*
  438.      * get integer portion of number; put into the end of the buffer; the
  439.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  440.      */
  441.     for (p = endp - 1; integer; ++expcnt) {
  442.         tmp = modf(integer / 10, &integer);
  443.         *p-- = tochar((int)((tmp + .01) * 10));
  444.     }
  445.     switch(fmtch) {
  446.     case 'f':
  447.         /* reverse integer into beginning of buffer */
  448.         if (expcnt)
  449.             for (; ++p < endp; *t++ = *p);
  450.         else
  451.             *t++ = '0';
  452.         /*
  453.          * if precision required or alternate flag set, add in a
  454.          * decimal point.
  455.          */
  456.         if (prec || flags&ALT)
  457.             *t++ = '.';
  458.         /* if requires more precision and some fraction left */
  459.         if (fract) {
  460.             if (prec)
  461.                 do {
  462.                     fract = modf(fract * 10, &tmp);
  463.                     *t++ = tochar((int)tmp);
  464.                 } while (--prec && fract);
  465.             if (fract)
  466.                 startp = round(fract, (int *)NULL, startp,
  467.                     t - 1, (char)0, signp);
  468.         }
  469.         for (; prec--; *t++ = '0');
  470.         break;
  471.     case 'e':
  472.     case 'E':
  473. eformat:    if (expcnt) {
  474.             *t++ = *++p;
  475.             if (prec || flags&ALT)
  476.                 *t++ = '.';
  477.             /* if requires more precision and some integer left */
  478.             for (; prec && ++p < endp; --prec)
  479.                 *t++ = *p;
  480.             /*
  481.              * if done precision and more of the integer component,
  482.              * round using it; adjust fract so we don't re-round
  483.              * later.
  484.              */
  485.             if (!prec && ++p < endp) {
  486.                 fract = 0;
  487.                 startp = round((double)0, &expcnt, startp,
  488.                     t - 1, *p, signp);
  489.             }
  490.             /* adjust expcnt for digit in front of decimal */
  491.             --expcnt;
  492.         }
  493.         /* until first fractional digit, decrement exponent */
  494.         else if (fract) {
  495.             /* adjust expcnt for digit in front of decimal */
  496.             for (expcnt = -1;; --expcnt) {
  497.                 fract = modf(fract * 10, &tmp);
  498.                 if (tmp)
  499.                     break;
  500.             }
  501.             *t++ = tochar((int)tmp);
  502.             if (prec || flags&ALT)
  503.                 *t++ = '.';
  504.         }
  505.         else {
  506.             *t++ = '0';
  507.             if (prec || flags&ALT)
  508.                 *t++ = '.';
  509.         }
  510.         /* if requires more precision and some fraction left */
  511.         if (fract) {
  512.             if (prec)
  513.                 do {
  514.                     fract = modf(fract * 10, &tmp);
  515.                     *t++ = tochar((int)tmp);
  516.                 } while (--prec && fract);
  517.             if (fract)
  518.                 startp = round(fract, &expcnt, startp,
  519.                     t - 1, (char)0, signp);
  520.         }
  521.         /* if requires more precision */
  522.         for (; prec--; *t++ = '0');
  523.  
  524.         /* unless alternate flag, trim any g/G format trailing 0's */
  525.         if (gformat && !(flags&ALT)) {
  526.             while (t > startp && *--t == '0');
  527.             if (*t == '.')
  528.                 --t;
  529.             ++t;
  530.         }
  531.         t = exponent(t, expcnt, fmtch);
  532.         break;
  533.     case 'g':
  534.     case 'G':
  535.         /* a precision of 0 is treated as a precision of 1. */
  536.         if (!prec)
  537.             ++prec;
  538.         /*
  539.          * ``The style used depends on the value converted; style e
  540.          * will be used only if the exponent resulting from the
  541.          * conversion is less than -4 or greater than the precision.''
  542.          *    -- ANSI X3J11
  543.          */
  544.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  545.             /*
  546.              * g/G format counts "significant digits, not digits of
  547.              * precision; for the e/E format, this just causes an
  548.              * off-by-one problem, i.e. g/G considers the digit
  549.              * before the decimal point significant and e/E doesn't
  550.              * count it as precision.
  551.              */
  552.             --prec;
  553.             fmtch -= 2;        /* G->E, g->e */
  554.             gformat = 1;
  555.             goto eformat;
  556.         }
  557.         /*
  558.          * reverse integer into beginning of buffer,
  559.          * note, decrement precision
  560.          */
  561.         if (expcnt)
  562.             for (; ++p < endp; *t++ = *p, --prec);
  563.         else
  564.             *t++ = '0';
  565.         /*
  566.          * if precision required or alternate flag set, add in a
  567.          * decimal point.  If no digits yet, add in leading 0.
  568.          */
  569.         if (prec || flags&ALT) {
  570.             dotrim = 1;
  571.             *t++ = '.';
  572.         }
  573.         else
  574.             dotrim = 0;
  575.         /* if requires more precision and some fraction left */
  576.         if (fract) {
  577.             if (prec) {
  578.                 do {
  579.                     fract = modf(fract * 10, &tmp);
  580.                     *t++ = tochar((int)tmp);
  581.                 } while(!tmp);
  582.                 while (--prec && fract) {
  583.                     fract = modf(fract * 10, &tmp);
  584.                     *t++ = tochar((int)tmp);
  585.                 }
  586.             }
  587.             if (fract)
  588.                 startp = round(fract, (int *)NULL, startp,
  589.                     t - 1, (char)0, signp);
  590.         }
  591.         /* alternate format, adds 0's for precision, else trim 0's */
  592.         if (flags&ALT)
  593.             for (; prec--; *t++ = '0');
  594.         else if (dotrim) {
  595.             while (t > startp && *--t == '0');
  596.             if (*t != '.')
  597.                 ++t;
  598.         }
  599.     }
  600.     return(t - startp);
  601. }
  602.  
  603. static char *
  604. round(fract, exp, start, end, ch, signp)
  605.     double fract;
  606.     int *exp;
  607.     register char *start, *end;
  608.     char ch, *signp;
  609. {
  610.     double tmp;
  611.  
  612.     if (fract)
  613.         (void)modf(fract * 10, &tmp);
  614.     else
  615.         tmp = todigit(ch);
  616.     if (tmp > 4)
  617.         for (;; --end) {
  618.             if (*end == '.')
  619.                 --end;
  620.             if (++*end <= '9')
  621.                 break;
  622.             *end = '0';
  623.             if (end == start) {
  624.                 if (exp) {    /* e/E; increment exponent */
  625.                     *end = '1';
  626.                     ++*exp;
  627.                 }
  628.                 else {        /* f; add extra digit */
  629.                     *--end = '1';
  630.                     --start;
  631.                 }
  632.                 break;
  633.             }
  634.         }
  635.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  636.     else if (*signp == '-')
  637.         for (;; --end) {
  638.             if (*end == '.')
  639.                 --end;
  640.             if (*end != '0')
  641.                 break;
  642.             if (end == start)
  643.                 *signp = 0;
  644.         }
  645.     return(start);
  646. }
  647.  
  648. static char *
  649. exponent(p, exp, fmtch)
  650.     register char *p;
  651.     register int exp;
  652.     char fmtch;
  653. {
  654.     register char *t;
  655.     char expbuf[MAXEXP];
  656.  
  657.     *p++ = fmtch;
  658.     if (exp < 0) {
  659.         exp = -exp;
  660.         *p++ = '-';
  661.     }
  662.     else
  663.         *p++ = '+';
  664.     t = expbuf + MAXEXP;
  665.     if (exp > 9) {
  666.         do {
  667.             *--t = tochar(exp % 10);
  668.         } while ((exp /= 10) > 9);
  669.         *--t = tochar(exp);
  670.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  671.     }
  672.     else {
  673.         *p++ = '0';
  674.         *p++ = tochar(exp);
  675.     }
  676.     return(p);
  677. }
  678. #endif /* __FLOATS__ */
  679.